# PYMT Plugin integration
IS_PYMT_PLUGIN = True
PLUGIN_TITLE = 'Napier Browser'
PLUGIN_AUTHOR = 'Jay Bradley'
PLUGIN_DESCRIPTION = 'Browse through file and search web resources'

from pymt import *
import os
import random
from OpenGL.GL import *
import copy
import Image
from pymt.lib.transformations import *
import MTTouchAndShowButton

current_dir = os.path.dirname(__file__)

class MTNapierInnerWindow(MTInnerWindow):

    def __init__(self, **kwargs):
        #print "MTNapierInnerWindow constructed"
        kwargs.setdefault('scale_min', 0.5)
        kwargs.setdefault('scale_max', 2)
        self.height_max = 600
        self.height_min = 100
        self.width_max = 600
        self.width_min = 300
        self.grow_delta = Vector(0, 0)
        self.aspect_controls_touches = {}
        self.window_controls_touches = []
        super(MTNapierInnerWindow, self).__init__(**kwargs)
        
        self.add_hold_aspect_ratio_controls()
        self.add_window_controls()
        
        # animate the appearance of the window
        self.scale_min_old = self.scale_min
        self.scale_min = 0.01
        self.scale = 0.01
        self.show_window_anim = Animation(duration=0.5, scale = 1, f = "ease_out_elastic")
        @self.show_window_anim.event
        def on_complete(self):
            self.scale_min = self.scale_min_old
            self.update_aspect_controls()
            self.update_window_controls()
            self.window_controls.visible = True
            #print "Show window anim complete"
        self.do(self.show_window_anim)
        self.is_fullscreen = False
        #print "Leaving MTNapierInnerWindow constructor"


    def close(self, touch):
        # stop any videos in this window otherwise they'll keep playing
        
        if(self.is_fullscreen == True):
            self.unfullscreen()
        
        print "MTNapierInnerWindow hack to stop any videos playing when the window is closed"
        self.stop_videos_hack(self.container)

        # animate the closing of the window
        self.width_min = 1
        self.height_min = 1
        self.scale_min = 0.01
        self.closing_anim = Animation(duration=0.2, scale=0.01, f = "ease_in_quad")
        @self.closing_anim.event
        def on_complete(self):
            super(MTNapierInnerWindow, self).close(touch)
        self.do(self.closing_anim)


    def stop_videos_hack(self, starting_widget):
        #print "MTNapierInnerWindow::stop_videos_hack starting_widget.__class__.__name__ is ", starting_widget.__class__.__name__

        if(starting_widget.__class__.__name__ == "MTVideo"):
            starting_widget.player.stop()
        for content in starting_widget.children:
            self.stop_videos_hack(content)

    def fullscreen(self, *largs, **kwargs):
        #root_win = self.parent.get_parent_window()
        root_win = self.parent

        # save state for restore
        self.old_children = root_win.children
        self.old_size = self.size
        self.old_center = self.center
        self.old_rotation = self.rotation
        self.old_scale = self.scale 

        self.hide_hold_aspect_ratio_controls()

        rotation_to_nearest_90 = int(round(self.rotation / 90, 0)) * 90
        
        if(rotation_to_nearest_90 == 360):
           rotation_to_nearest_90 = 0
            
        #print "rotation_to_nearest_90:", rotation_to_nearest_90

        #self.orientation_widget = MTScatterWidget(size = self.parent.get_parent_window().size, rotation = rotation_to_nearest_90) # round rotation to nearest compass point
        target_size = self.parent.get_parent_window().size
        if(rotation_to_nearest_90 == 0 or rotation_to_nearest_90 == 360):
            pass
        elif(rotation_to_nearest_90 == 90):
            target_size = self.parent.get_parent_window().size[1], self.parent.get_parent_window().size[0]
        elif(rotation_to_nearest_90 == 180):
            pass
        elif(rotation_to_nearest_90 == 270):
            target_size = self.parent.get_parent_window().size[1], self.parent.get_parent_window().size[0]
            

        # do animation here then everything else afterwards
        # bring to front
        self.bring_to_front()
        
        # change size
        self.window_zoom_fullscreen_anim = Animation(duration=0.5, size=target_size, scale=1, f = "ease_in_quad")
        self.container_zoom_fullscreen_anim = Animation(duration=0.5, size=target_size, f = "ease_in_quad")
        self.do(self.window_zoom_fullscreen_anim)
        self.container.do(self.container_zoom_fullscreen_anim)

               
        #change position
        self.window_move_fullscreen_anim = Animation(duration=0.5, center=(self.parent.get_parent_window().center), f = "ease_in_quad")
        #self.window_move_fullscreen_anim = Animation(duration=0.5, center=(0,0), f = "ease_in_quad")
        
        # change rotation
        relative_rotation_needed = rotation_to_nearest_90 - self.rotation
        if(abs(relative_rotation_needed) > 180):
            relative_rotation_needed = 360 - (-1 * relative_rotation_needed)
        self.window_rotate_fullscreen_anim = Animation(duration=0.5, type="delta", rotation=(relative_rotation_needed), f = "ease_in_quad")
        
        self.window_move_rotate_fullscreen_anim = self.window_move_fullscreen_anim & self.window_rotate_fullscreen_anim
        @self.window_move_rotate_fullscreen_anim.event
        def on_complete(self):

            # set new children
            #root_win.children = SafeList()
            #self.orientation_widget.add_widget(self.container)
            #root_win.add_widget(self.orientation_widget)
            self.is_fullscreen = True
            
            ##btn_unfullscreen = MTImageButton(pos=(self.orientation_widget.width-50, self.orientation_widget.height-50), size=(50,50), filename="resources/graphics/unfullscreen.png")
            ##btn_unfullscreen.push_handlers(on_release=self.unfullscreen)
            ##root_win.add_widget(btn_unfullscreen)
            ##self.orientation_widget.add_widget(btn_unfullscreen)
            
        self.do(self.window_move_rotate_fullscreen_anim)
        
        


    def unfullscreen(self, *largs, **kwargs):
        # restore old widget
        #root_win = self.parent.get_parent_window()
        #root_win = self.parent
        #root_win.children = self.old_children

        # reset container parent
        #self.container.parent = self

        if(self.rotation == 360):
            self.rotation = 0
        rotation_to_get_back = self.old_rotation - self.rotation
        if (rotation_to_get_back > 180):
             rotation_to_get_back -= 360
        if (rotation_to_get_back < -180):
             rotation_to_get_back += 360

        self.window_zoom_fullscreen_anim = Animation(duration=0.5, size=self.old_size, scale=self.old_scale, f = "ease_out_elastic")
        self.do(self.window_zoom_fullscreen_anim)
        
        self.window_container_zoom_fullscreen_anim = Animation(duration=0.5, size=(self.old_size), f = "ease_in_quad")
        self.container.do(self.window_container_zoom_fullscreen_anim)
        
        self.window_move_fullscreen_anim = Animation(duration=0.5, center=(self.old_center), rotation=(self.rotation + rotation_to_get_back), f = "ease_out_elastic")
        @self.window_move_fullscreen_anim.event
        def on_complete(self):
            self.is_fullscreen = False
            self.show_hold_aspect_ratio_controls()
        
        self.do(self.window_move_fullscreen_anim)
        
        

    def add_hold_aspect_ratio_controls(self):
        scaled_border = self.get_scaled_border()

        self.aspect_controls = MTWidget()
        #self.aspect_controls.fixed_scale = 1 # this value is used to fix the scaling of the window controls # can't use now as MTWidget uses __slots__
        

#        self.aspect_control_bottom_left = MTButton(pos=(-scaled_border, -scaled_border), size = (scaled_border, scaled_border), cls="aspect_ratio_controls")
#        self.aspect_controls.add_widget(self.aspect_control_bottom_left)
#
#        self.aspect_control_top_left = MTButton(pos=(-scaled_border, self.height), size = (scaled_border, scaled_border), cls="aspect_ratio_controls")
#        self.aspect_controls.add_widget(self.aspect_control_top_left)

#        self.aspect_control_bottom_right = MTButton(pos=(self.width, -scaled_border), size = (scaled_border, scaled_border), cls="aspect_ratio_controls")
#        self.aspect_controls.add_widget(self.aspect_control_bottom_right)

        self.aspect_control_top_right = MTImageButton(filename="resources/graphics/aspectControlButtonTextureRoundDots.png", pos=(self.width, self.height), size = (scaled_border, scaled_border), cls="aspect_ratio_controls")
        self.aspect_controls.add_widget(self.aspect_control_top_right)
        
        self.add_widget(self.aspect_controls) # not sure if this is needed. Works without it.

    def add_window_controls(self):
        scaled_border = self.get_scaled_border()
        self.window_controls = MTTouchAndShowButton.MTTouchAndShowButton(filename="resources/graphics/aspectControlButtonTextureBottomDots.png", start_angle = 150, end_angle = 210)#, sub_buttons_radius_extra_spacing = 50)
        self.window_controls.visible = False
        #self.window_controls.fixed_scale = 1 # this value is used to fix the scaling of the window controls. MTWidget __slots__
        self.add_widget(self.window_controls) # not sure if this is needed. Works without it.
        self.window_controls.add_sub_button("resources/graphics/fullscreen.png", self.fullscreen)
        self.window_controls.add_sub_button("resources/graphics/close.png", self.close)

    def hide_hold_aspect_ratio_controls(self):
        self.aspect_controls.visible = False

    def show_hold_aspect_ratio_controls(self):
        self.aspect_controls.visible = True

    def update_window_controls(self):
        #print "MTNapierInnerWindow::update_window_controls"
        # hack to lock the window controls to stay the same size when the window is resized
        scaled_border = self.get_scaled_border()
        self.window_controls.scale = 1.0 / self.scale # do not scale the window controls
        for child in self.window_controls.children:
            child.scale = 1.0 / self.scale # do not scale the window controls
        self.window_controls.pos = ((self.width / 2) - (self.window_controls.width / 2), (-scaled_border / 2) - (self.window_controls.height / 2))

    def update_aspect_controls(self):
        scaled_border = self.get_scaled_border()
        # hack to lock the window controls to stay the same size when the window is resized
        for child in self.aspect_controls.children:
            child.scale = 1.0 / self.scale # do not scale the aspect controls

#        self.aspect_control_bottom_left.pos = (-scaled_border * scale_of_aspect_controls, -scaled_border * scale_of_aspect_controls)
#        self.aspect_control_bottom_left.size = (size_of_aspect_controls, size_of_aspect_controls)
#
#        self.aspect_control_top_left.pos = (-scaled_border * scale_of_aspect_controls, self.height)
#        self.aspect_control_top_left.size = (size_of_aspect_controls, size_of_aspect_controls)
#
#        self.aspect_control_bottom_right.pos = (self.width, -scaled_border * scale_of_aspect_controls)
#        self.aspect_control_bottom_right.size = (size_of_aspect_controls, size_of_aspect_controls)

        self.aspect_control_top_right.pos = (self.width, self.height)


    def on_touch_down(self, touch):

        #print "MTNapierInnerWindow::on_touch_down"

        # if the touch isn't on the widget we do nothing
        if not self.collide_point(touch.x, touch.y):
            #print "touch not on inner window"
            MTInnerWindow.on_touch_down(self, touch)
            return False

        local_touch = self.to_local(touch.x, touch.y)

        if(self.window_controls.collide_point(local_touch[0], local_touch[1])):
            #print "windows controls touched"
            self.window_controls.on_press(local_touch)
            self.window_controls_touches.append(touch.id)
            return True

        if(len(self.aspect_controls_touches.keys()) == 0): # only one touch allowed at a time on the aspect ratio controls
            #print "len(self.aspect_controls_touches.keys()) == 0 is true"
            if(self.aspect_control_top_right.collide_point(local_touch[0], local_touch[1])):
                #print "touch on aspect control"
                #print "MTNapierInnerWindow touch down over top right aspect control"
                self.aspect_controls_touches[touch.id] = ["top", "right"]
#            elif(self.aspect_control_top_left.collide_point(local_touch[0], local_touch[1])):
#                #print "MTNapierInnerWindow touch down over top left aspect control"
#                self.aspect_controls_touches[touch.id] = ["top", "left"]
#            elif(self.aspect_control_bottom_right.collide_point(local_touch[0], local_touch[1])):
#                #print "MTNapierInnerWindow touch down over bottom right aspect control"
#                self.aspect_controls_touches[touch.id] = ["bottom", "right"]
#            elif(self.aspect_control_bottom_left.collide_point(local_touch[0], local_touch[1])):
#                #print "MTNapierInnerWindow touch down over bottom left aspect control"
#                self.aspect_controls_touches[touch.id] = ["bottom", "left"]

            #else:
                #'print "MTNapierInnerWindow touch down NOT over aspect controls"
        return MTInnerWindow.on_touch_down(self, touch) # the "return" lets MTInnerWindow deal with the touch
        #return True # don't let this touch get sent to any other widget. This was a mistake as it stops any of this window's children receiving the event.


    def on_touch_up(self, touch):
        # if touch in self.aspect_controls_touches then remove it
        if(touch.id in self.aspect_controls_touches.keys()):
            del self.aspect_controls_touches[touch.id]

        if(touch.id in self.window_controls_touches):
            local_touch_pos = self.to_local(touch.x, touch.y)
            local_touch = copy.deepcopy(touch)
            local_touch.x = local_touch_pos[0]
            local_touch.y = local_touch_pos[1]
            self.window_controls_touches.remove(touch.id)
            self.window_controls.on_release(local_touch)

        return MTInnerWindow.on_touch_up(self, touch)

    def change_aspect_ratio(self, touch):
        dx = (touch.x - touch.dxpos) * self._do_translation_x
        dy = (touch.y - touch.dypos) * self._do_translation_y
        
        grow_delta = Vector(dx, dy)
        grow_delta = grow_delta.rotate(360.0 - self.rotation)

        aspect_control_location = self.aspect_controls_touches.items()[0][1]

        # handle switch in direction of growth
        # left
        if("left" in aspect_control_location):
            grow_delta[0] *= -1.0
        # bottom
        if("bottom" in aspect_control_location):
            grow_delta[1] *= -1.0

        # change the size
        self.width += grow_delta[0]
        self.height += grow_delta[1]

        # offset the window
        dx = 0
        dy = 0
        # left
        if("left" in aspect_control_location):
            trans.x = -grow_delta[0]
        # bottom
        if("bottom" in aspect_control_location):
            trans.y = -grow_delta[1]

        # check that the widget isn't too small or too large
        if(self.height <= self.height_min):
            self.height = self.height_min
        elif(self.height >= self.height_max):
            self.height = self.height_max
        if(self.width <= self.width_min):
            self.width = self.width_min
        elif(self.width >= self.width_max):
            self.width = self.width_max

        # resize the widget's container too
        self.container.height = self.height
        self.container.width = self.width

        self.apply_transform(translation_matrix((dx,dy,0)))
        
    def transform_with_touch(self, touch):
        # intercept the usual zooming and change the size of the window instead
        if(len(self.aspect_controls_touches.keys()) >= 1 and len(self._touches) == 1):    # change size rather than scale
            #print "change shape not size"
            self.change_aspect_ratio(touch)
            #dispatch on_transform with th touch that caused it
            self.dispatch_event('on_transform', touch)
        else:
            super(MTNapierInnerWindow, self).transform_with_touch(touch)

    def on_transform(self, touch):
        #print "MTNapierInnerWindow::on_transform"
        self.update_aspect_controls()
        self.update_window_controls()
        

    def draw(self):
        MTInnerWindow.draw(self)
        self.window_controls.dispatch_event('on_draw')
        self.aspect_controls.dispatch_event('on_draw')


